/**
 ******************************************************************************
 * @file    zb32l03x_hal_uart_irda.c
 * @author  MCU Application Team
 * @Version V0.0.1
 * @Date    2022/12/30
 * @brief   USART IrDA HAL module driver.
 @verbatim
 ******************************************************************************
 **/
#include "zb32l03x_hal.h"

#if defined(HAL_USART_IRDA_MODULE_ENABLE)
/** @addtogroup USART_IrDA
  * @brief USART_IrDA HAL module driver.
  * @{
  */

//=============================================================================
//                         Constant Definition
//=============================================================================
/** @defgroup  USART Write Data to DR Register for Transmit or Receive Data Length Mask definition.
  * @{
  */

#define USART_IRDA_DR_7BIT                           (0x007fUL)
#define USART_IRDA_DR_8BIT                           (0x00ffUL)
#define USART_IRDA_DR_9BIT                           (0x01ffUL)

//=============================================================================
//                          Macro Definition
//=============================================================================


//=============================================================================
//                        Structure Definition
//=============================================================================


//=============================================================================
//                       Global Data Definition
//=============================================================================


//=============================================================================
//                     Private Function Definition
//=============================================================================
/**
  * @brief  Configures the USART IrDA peripheral.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART IrDA module.
  * @retval None
  */
static void
_USART_IRDA_SetConfig(USART_IrDA_HandleTypeDef *phirda)
{
    uint32_t pclk       = 0U;
    uint32_t mantissa   = 0U;
    uint32_t fraciton   = 0U;

    /* Config IrDA Transfer Baud Rate Division Value. */
    pclk = HAL_RCC_GetPCLKFreq();

    mantissa = pclk / (16U * (phirda->Init.BaudRate));     //(Tx or Rx) Div = Fsclk / (16*BaudRate)

    MODIFY_REG(phirda->Instance->BRR,
               (USART_BRR_DIV_Mantissa),
               (uint32_t)(mantissa << USART_BRR_DIV_Mantissa_Pos));

    fraciton = (pclk / phirda->Init.BaudRate);

    fraciton = (fraciton > (mantissa * 16U)) ? (fraciton - (mantissa * 16U)) : ((mantissa * 16U) - fraciton);

    MODIFY_REG(phirda->Instance->BRR,
               (USART_BRR_DIV_Fraction),
               (uint32_t)((fraciton << USART_BRR_DIV_Fraction_Pos) & USART_BRR_DIV_Fraction_Msk));

    /* Config IrDA Transfer Prescaler. */
    WRITE_REG(phirda->Instance->GTPR, phirda->Init.Prescaler);

    /* Config IrDA Operating Mode */
    MODIFY_REG(phirda->Instance->CR3,
               USART_CR3_IRLP,
               phirda->Init.PowerMode);

    CLEAR_BIT(phirda->Instance->CR2, USART_CR2_STOP);

    MODIFY_REG(phirda->Instance->CR1,
               (USART_CR1_M | USART_CR1_PCE | USART_CR1_PS | USART_CR1_TE | USART_CR1_RE),
               (phirda->Init.Mode | phirda->Init.Parity | phirda->Init.WordLength));

    return;
}



/**
  * @brief  The USART IrDA module uses interrupt handling to send data once.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_IRDA_Transmit_IT(USART_IrDA_HandleTypeDef *phirda)
{
    uint16_t tmp = 0U;

    if( phirda->gState != HAL_USART_IRDA_STATE_BUSY_TX )
    {
        CLEAR_BIT(phirda->Instance->CR1, (USART_CR1_TCIE | USART_CR1_TXEIE));

        __HAL_USART_IRDA_CLEAR_FLAG(phirda, USART_IRDA_FLAG_TXE);
        __HAL_USART_IRDA_CLEAR_FLAG(phirda, USART_IRDA_FLAG_TC);

        return HAL_BUSY;
    }

    if( !phirda->TxXferCount )
    {
        CLEAR_BIT(phirda->Instance->CR1, USART_CR1_TXEIE);

        __HAL_USART_IRDA_CLEAR_FLAG(phirda, USART_IRDA_FLAG_TC);

        return HAL_OK;
    }

    if( phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
        phirda->Init.Parity == USART_IRDA_PARITY_NONE )
    {
        tmp = (*((uint16_t *)(phirda->pTxBuffPtr)) & USART_IRDA_DR_9BIT);

        phirda->pTxBuffPtr += 2;
    }
    else if( (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
              phirda->Init.Parity != USART_IRDA_PARITY_NONE) ||
             (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_8B &&
              phirda->Init.Parity == USART_IRDA_PARITY_NONE) )
    {
        tmp = (*phirda->pTxBuffPtr) & USART_IRDA_DR_8BIT;

        phirda->pTxBuffPtr++;
    }
    else
    {
        tmp = (*phirda->pTxBuffPtr) & USART_IRDA_DR_7BIT;

        phirda->pTxBuffPtr++;
    }

    WRITE_REG(phirda->Instance->DR, tmp);
    phirda->TxXferCount--;

    return HAL_OK;
}

/**
  * @brief  The USART IrDA module uses interrupt handling to receive data once.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_IRDA_Receive_IT(USART_IrDA_HandleTypeDef *phirda)
{
    uint16_t tmp = 0U;

    if( phirda->RxState != HAL_USART_IRDA_STATE_BUSY_RX ||
        !phirda->RxXferCount )
    {
        CLEAR_BIT(phirda->Instance->CR1, USART_CR1_RXNEIE);

        __HAL_USART_IRDA_CLEAR_FEFLAG(phirda);

        return HAL_BUSY;
    }

    tmp = phirda->Instance->DR;

    if( phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
        phirda->Init.Parity == USART_IRDA_PARITY_NONE )
    {
        *((uint16_t *)phirda->pRxBuffPtr) = (tmp & USART_IRDA_DR_9BIT);

        phirda->pRxBuffPtr += 2U;
    }
    else if( (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
              phirda->Init.Parity != USART_IRDA_PARITY_NONE) ||
             (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_8B &&
              phirda->Init.Parity == USART_IRDA_PARITY_NONE) )
    {
        *phirda->pRxBuffPtr = (tmp & USART_IRDA_DR_8BIT);

        phirda->pRxBuffPtr++;
    }
    else
    {
        *phirda->pRxBuffPtr = (tmp & USART_IRDA_DR_7BIT);

        phirda->pRxBuffPtr++;
    }

    phirda->RxXferCount--;

    if( !phirda->RxXferCount )
    {
        CLEAR_BIT(phirda->Instance->CR1, (USART_CR1_RXNEIE| USART_CR1_PEIE_Msk) );
        CLEAR_BIT(phirda->Instance->CR3, (USART_CR3_EIE_Msk) );

        phirda->RxState = HAL_USART_IRDA_STATE_READY;
    }

    return HAL_OK;
}

/**
  * @brief  Read the value of the SR register to obtain the status of the interrupt bit.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL status
  */
static HAL_StatusTypeDef
_USART_IRDA_WaitOnFlagUntilTimeout(
        USART_IrDA_HandleTypeDef    *phirda,
        uint32_t                    Flag,
        FlagStatus                  Status,
        uint32_t                    Tickstart,
        uint32_t                    Timeout)
{
    /* Wait until flag is set */
    while ( (__HAL_USART_IRDA_GET_FLAG(phirda, Flag) ? SET : RESET) == Status )
    {
        /* Check for the Timeout */
        if ( (Timeout != HAL_MAX_DELAY) && ((Timeout == 0U) ||
                                            ((HAL_GetTick() - Tickstart) > Timeout)) )
        {
            /* Disable the USART TC/TXE/RXNE/PEIE/EIE Interrupt */
            CLEAR_BIT( phirda->Instance->CR1, (USART_CR1_TCIE_Msk | USART_CR1_TXEIE_Msk | USART_CR1_RXNEIE_Msk | USART_CR1_PEIE_Msk) );
            CLEAR_BIT( phirda->Instance->CR3, (USART_CR3_EIE_Msk) );

            phirda->gState = HAL_USART_IRDA_STATE_READY;
            phirda->RxState = HAL_USART_IRDA_STATE_READY;

            return HAL_TIMEOUT;
        }
    }

    return HAL_OK;
}

#if defined(HAL_DMA_MODULE_ENABLED)

/**
  * @brief  Gets the channel that USART IrDA uses to transmit data using PDMA.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  Status    USART IrDA work state.
  *                     @arg HAL_USART_IRDA_STATE_BUSY_TX: USART will send data.
  *                     @arg HAL_USART_IRDA_STATE_BUSY_RX: USART will receive data.
  * @param  ChannelID PDMA module channel.
  * @retval HAL DMA Channel
  */
static HAL_StatusTypeDef
_USART_IRDA_GetPDMAChannel(
        USART_IrDA_HandleTypeDef    *phirda,
        HAL_USART_IrDA_StateTypeDef Status,
        HAL_DMA_Channel_TypeDef     *ChannelID)
{
    HAL_StatusTypeDef IsOK = HAL_OK;

    if( phirda->Instance == USART2 )
    {
        if( Status == HAL_USART_IRDA_STATE_BUSY_TX )
        {
            *ChannelID = HAL_DMA_CHANNEL_USART2_TX;
        }
        else if( Status == HAL_USART_IRDA_STATE_BUSY_RX )
        {
            *ChannelID = HAL_DMA_CHANNEL_USART2_RX;
        }
        else
        {
            IsOK = HAL_ERROR;
        }
    }
    else if( phirda->Instance == USART3 )
    {
        if( Status == HAL_USART_IRDA_STATE_BUSY_TX )
        {
            *ChannelID = HAL_DMA_CHANNEL_USART3_TX;
        }
        else if( Status == HAL_USART_IRDA_STATE_BUSY_RX )
        {
            *ChannelID = HAL_DMA_CHANNEL_USART3_RX;
        }
        else
        {
            IsOK = HAL_ERROR;
        }
    }
    else
    {
        IsOK = HAL_ERROR;
    }

    return IsOK;
}

/**
  * @brief  Configure the working parameters of the DMA channel when USART IrDA sends data.
  * @param  phirda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
static HAL_StatusTypeDef
_USART_IRDA_Transmit_DMA_Config(
                                USART_IrDA_HandleTypeDef *phirda)
{
    HAL_DMA_Descriptor_Cfg_TypeDef  hpdma_channel_config    = {0};
    HAL_DMA_Xfer_Cfg_TypeDef        hpdma_tran_data_config  = {0};
    HAL_DMA_Channel_TypeDef         channelid;
    HAL_StatusTypeDef               rval                    = HAL_OK;

    if( !phirda ||
        !phirda->pTxBuffPtr ||
        !phirda->TxXferCount )
    {
        return HAL_ERROR;
    }

    if( _USART_IRDA_GetPDMAChannel(phirda, phirda->gState, &channelid) != HAL_OK )
    {
        return HAL_ERROR;
    }

    //Config PDMA work infomation in SRAM.
    hpdma_channel_config.xfer_bytes = phirda->TxXferCount;
    hpdma_channel_config.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_channel_config.dst_inc    = DMA_DATA_INC_NONE;
    hpdma_channel_config.arbit_rate = DMA_ARBITRATION_RATE_1;
    hpdma_channel_config.timeout    = -1;
    hpdma_channel_config.src_addr   = (void *)(phirda->pTxBuffPtr);
    hpdma_channel_config.dst_addr   = (void *)&(phirda->Instance->DR);
    if( (phirda->Init.Parity == USART_IRDA_PARITY_NONE) &&
        (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B) )
    {
        hpdma_channel_config.src_inc = DMA_DATA_INC_HALFWORD;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_HALFWORD;
        hpdma_channel_config.xfer_bytes = (phirda->TxXferCount * 2);
    }
    else
    {
        hpdma_channel_config.src_inc = DMA_DATA_INC_BYTE;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_BYTE;
    }

    rval = HAL_DMA_Set_Descriptor(phirda->pHDma, channelid, &hpdma_channel_config, NULL);
    if( rval != HAL_OK )
    {
        return rval;
    }

    //Config PDMA ready work.
    hpdma_tran_data_config.is_immediate = RESET;
    hpdma_tran_data_config.mode         = HAL_DMA_MODE_BASIC;
    hpdma_tran_data_config.timeout      = -1;
    hpdma_tran_data_config.type         = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_tran_data_config.user_data    = phirda->TxXferCount;

    rval = HAL_DMA_Channel_Sart(phirda->pHDma, channelid, &hpdma_tran_data_config);

    return rval;
}

/**
  * @brief  Configure the working parameters of the DMA channel when USART IrDA receives data.
  * @param  phirda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
static HAL_StatusTypeDef
_USART_IRDA_Receive_DMA_Config(
                                USART_IrDA_HandleTypeDef *phirda)
{
    HAL_DMA_Descriptor_Cfg_TypeDef  hpdma_channel_config    = {0};
    HAL_DMA_Xfer_Cfg_TypeDef        hpdma_tran_data_config  = {0};
    HAL_StatusTypeDef               rval                    = HAL_OK;
    HAL_DMA_Channel_TypeDef         channelid;

    if( !phirda ||
        !phirda->RxXferCount ||
        !phirda->pRxBuffPtr )
    {
        return HAL_ERROR;
    }

    if( _USART_IRDA_GetPDMAChannel(phirda, phirda->RxState, &channelid) != HAL_OK )
    {
        return HAL_ERROR;
    }

    //Config PDMA work infomation in SRAM.
    hpdma_channel_config.arbit_rate = DMA_ARBITRATION_RATE_1;
    hpdma_channel_config.dst_addr   = (void *)(phirda->pRxBuffPtr);
    hpdma_channel_config.src_addr   = (void *)&(phirda->Instance->DR);
    hpdma_channel_config.src_inc    = DMA_DATA_INC_NONE;
    hpdma_channel_config.timeout    = -1;
    hpdma_channel_config.type       = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_channel_config.xfer_bytes = phirda->RxXferCount;
    if( (phirda->Init.Parity == USART_IRDA_PARITY_NONE) &&
        (phirda->Init.WordLength == USART_IRDA_WORDLENGTH_9B) )
    {
        hpdma_channel_config.dst_inc = DMA_DATA_INC_HALFWORD;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_HALFWORD;
        hpdma_channel_config.xfer_bytes = (phirda->RxXferCount * 2);
    }
    else
    {
        hpdma_channel_config.dst_inc = DMA_DATA_INC_BYTE;
        hpdma_channel_config.unit_size = DMA_DATA_SIZE_BYTE;
    }

    rval = HAL_DMA_Set_Descriptor(phirda->pHDma, channelid, &hpdma_channel_config, NULL);
    if( rval != HAL_OK )
    {
        return rval;
    }

    //Config PDMA ready work.
    hpdma_tran_data_config.is_immediate = RESET;
    hpdma_tran_data_config.mode         = HAL_DMA_MODE_BASIC;
    hpdma_tran_data_config.timeout      = -1;
    hpdma_tran_data_config.type         = DMA_DESCRIPTOR_TYPE_PRIMARY;
    hpdma_tran_data_config.user_data    = phirda->RxXferCount;

    rval = HAL_DMA_Channel_Sart(phirda->pHDma, channelid, &hpdma_tran_data_config);

    return rval;
}

#endif /* End of HAL_DMA_MODULE_ENABLED */


//=============================================================================
//                          Public Function
//=============================================================================

/**
  * @brief  Initialize the USART IrDA peripheral.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Init(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Check handle is valid */
    if( !pHIrda || !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_IRDA_INSTANCE(pHIrda->Instance));
    assert_param(IS_USART_IRDA_BAUDRATE(pHIrda->Init.BaudRate));
    assert_param(IS_USART_IRDA_MODE(pHIrda->Init.Mode));
    assert_param(IS_USART_IRDA_PARITY(pHIrda->Init.Parity));
    assert_param(IS_USART_IRDA_WORDLENGTH(pHIrda->Init.WordLength));
    assert_param(IS_USART_IRDA_POWERMODE(pHIrda->Init.PowerMode));
    assert_param(IS_USART_IRDA_PRESCALER(pHIrda->Init.Prescaler));

    /* Enable module clock signal and configure related IO pins. */
    if( pHIrda->gState == HAL_USART_IRDA_STATE_RESET )
    {
        pHIrda->Lock = HAL_UNLOCKED;

        HAL_USART_IRDA_MspInit(pHIrda);
    }

    pHIrda->gState = HAL_USART_IRDA_STATE_BUSY;

    /* Prevent the module from taking actions that do not meet expectations. */
    __HAL_USART_IRDA_DISABLE(pHIrda);
    __HAL_USART_DISABLE(pHIrda);

    /* Initializes the module register configuration based on the parameters configured in the handle. */
    _USART_IRDA_SetConfig(pHIrda);

    /* Clears the module enabling bit data that is incompatible with synchronous mode. */
    CLEAR_BIT(pHIrda->Instance->CR2, (USART_CR2_CLKEN | USART_CR2_LINEN));
    CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_HDSEL | USART_CR3_IREN));

    /* The module is ready to work. */
    __HAL_USART_IRDA_ENABLE(pHIrda);
    __HAL_USART_ENABLE(pHIrda);

    /* Initialize the status parameters. */
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->gState      = HAL_USART_IRDA_STATE_READY;
    pHIrda->RxState     = HAL_USART_IRDA_STATE_READY;

    return HAL_OK;
}


/**
  * @brief  De-Initialize the USART IrDA peripheral.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_DeInit(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Check handle is valid */
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    /* Check whether the input parameters are valid. */
    assert_param(IS_USART_IRDA_INSTANCE(pHIrda->Instance));

    pHIrda->gState  = HAL_USART_IRDA_STATE_BUSY;
    pHIrda->RxState = HAL_USART_IRDA_STATE_BUSY;

    /* Disable module. */
    __HAL_USART_IRDA_DISABLE(pHIrda);
    __HAL_USART_DISABLE(pHIrda);

    /* Close the module clock and IO pins. */
    HAL_USART_IRDA_MspDeInit(pHIrda);

    /* Reset module status parameters. */
    pHIrda->gState = HAL_USART_IRDA_STATE_RESET;
    pHIrda->RxState = HAL_USART_IRDA_STATE_RESET;
    pHIrda->ErrorCode = HAL_USART_IRDA_ERROR_NONE;

    pHIrda->Lock = HAL_UNLOCKED;

    return HAL_OK;
}


/**
  * @brief  USART IrDA MSP Init.
  * @param  pHIrda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_IRDA_MspInit(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_USART_IRDA_MspInit could be implemented in the user file
    */
}

/**
  * @brief  USART IrDA MSP DeInit.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval None
  */
__weak void HAL_USART_IRDA_MspDeInit(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);
    /* NOTE: This function should not be modified, when the callback is needed,
             the HAL_USART_IRDA_MspDeInit could be implemented in the user file
    */
}


/**
  * @brief  Send an amount of data in blocking mode.
  * @note   When USART IrDA parity is not enabled, and word length is configured to 9 bits,
  *         the sent data is handled as a set of uint16. In this case, size must indicate the number
  *         of uint16 provided through pData.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @param  Timeout Timeout duration.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size, uint32_t TimeOut)
{
    HAL_StatusTypeDef   rval        = HAL_OK;
    uint32_t            tickstart   = 0U;
    uint16_t            *ptr16bits  = NULL;
    uint8_t             *ptr8bits   = NULL;

    if( !pHIrda || !pData || !Size || !TimeOut )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->TxXferCount = Size;
    pHIrda->TxXferSize  = Size;
    pHIrda->pTxBuffPtr  = pData;

    if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
        pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
    {
        ptr16bits = (uint16_t *)pData;
    }
    else
    {
        ptr8bits = pData;
    }

    tickstart = HAL_GetTick();

    while( pHIrda->TxXferCount )
    {
        rval = _USART_IRDA_WaitOnFlagUntilTimeout(pHIrda, USART_IRDA_FLAG_TXE, RESET, tickstart, TimeOut);
        if( rval != HAL_OK )
        {
            break;
        }

        if( ptr16bits )
        {
            WRITE_REG(pHIrda->Instance->DR, ((*ptr16bits) & USART_IRDA_DR_9BIT) );

            ptr16bits++;
        }
        else
        {
            if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B ||
                pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
            {
                WRITE_REG(pHIrda->Instance->DR, ((*ptr8bits) & USART_IRDA_DR_8BIT) );
            }
            else
            {
                WRITE_REG(pHIrda->Instance->DR, ((*ptr8bits) & USART_IRDA_DR_7BIT) );
            }

            ptr8bits++;
        }

        pHIrda->TxXferCount--;
    }

    __HAL_USART_IRDA_CLEAR_FLAG(pHIrda, USART_IRDA_FLAG_TC);

    rval = _USART_IRDA_WaitOnFlagUntilTimeout(pHIrda, USART_IRDA_FLAG_TC, RESET, tickstart, TimeOut);

    __HAL_UNLOCK(pHIrda);

    pHIrda->gState = HAL_USART_IRDA_STATE_READY;

    return rval;
}


/**
  * @brief  Receive an amount of data in blocking mode.
  * @note   When USART IrDA parity is not enabled, and word length is configured to 9 bits,
  *         the received data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 available through pData.
  * @param  pHIrda    Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout Timeout duration.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size, uint32_t TimeOut)
{
    HAL_StatusTypeDef   rval        = HAL_OK;
    uint32_t            tickstart   = 0U;
    uint16_t            *ptr16bits  = NULL;
    uint8_t             *ptr8bits   = NULL;

    if( !pHIrda || !pData || !Size || !TimeOut )
    {
        return HAL_ERROR;
    }

    if( pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->RxXferCount = Size;
    pHIrda->RxXferSize  = Size;
    pHIrda->pRxBuffPtr  = pData;

    __HAL_USART_IRDA_CLEAR_FEFLAG(pHIrda);

    if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B && pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
    {
        ptr16bits = (uint16_t *)pData;
    }
    else
    {
        ptr8bits = pData;
    }

    tickstart = HAL_GetTick();

    while( pHIrda->RxXferCount )
    {
        rval = _USART_IRDA_WaitOnFlagUntilTimeout(pHIrda, USART_IRDA_FLAG_RXNE, RESET, tickstart, TimeOut);
        if( rval != HAL_OK )
        {
            break;
        }

        if( __HAL_USART_IRDA_GET_FLAG(pHIrda, USART_IRDA_FLAG_FE) )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_FE;
        }

        if( ptr16bits )
        {
            *ptr16bits = (pHIrda->Instance->DR & USART_IRDA_DR_9BIT);

            ptr16bits++;
        }
        else
        {
            if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B ||
                pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
            {
                *ptr8bits = (pHIrda->Instance->DR & USART_IRDA_DR_8BIT);
            }
            else
            {
                *ptr8bits = (pHIrda->Instance->DR & USART_IRDA_DR_7BIT);
            }

            ptr8bits++;
        }

        pHIrda->RxXferCount--;
    }

    __HAL_UNLOCK(pHIrda);

    pHIrda->RxState = HAL_USART_IRDA_STATE_READY;

    return rval;
}


/**
  * @brief  Send and Receive an amount of data in IrDA mode (blocking mode).
  * @note   When USART IrDA parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data and the received data are handled as sets of uint16. In this case, Size must indicate the number
  *         of uint16 available through pTxData and through pRxData.
  * @param  pHIrda    Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to TX data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to RX data buffer (uint8 or uint16 data elements).
  * @param  TxSize  Amount of data elements (uint8 or uint16) to be sent.
  * @param  RxSize  Amount of data elements (uint8 or uint16) to be received.
  * @param  Timeout Timeout duration
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_TransmitReceive(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize, uint32_t TimeOut)
{
    HAL_StatusTypeDef   rval            = HAL_OK;
    uint32_t            tickstart       = 0U;
    uint16_t            *ptr16bitstx    = NULL;
    uint16_t            *ptr16bitsrx    = NULL;
    uint8_t             *ptr8bitstx     = NULL;
    uint8_t             *ptr8bitsrx     = NULL;

    if( !pHIrda || !TimeOut ||
        !pTxData || !TxSize ||
        !pRxData || !RxSize )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY ||
        pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->TxXferCount = TxSize;
    pHIrda->TxXferSize  = TxSize;
    pHIrda->RxXferCount = RxSize;
    pHIrda->RxXferSize  = RxSize;

    __HAL_USART_IRDA_CLEAR_FEFLAG(pHIrda);

    if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B &&
        pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
    {
        ptr16bitstx = (uint16_t *)pTxData;
        ptr16bitsrx = (uint16_t *)pRxData;
    }
    else
    {
        ptr8bitstx = pTxData;
        ptr8bitsrx = pRxData;
    }

    tickstart = HAL_GetTick();

    while( (pHIrda->TxXferCount || pHIrda->RxXferCount) &&
            ((HAL_GetTick() - tickstart) < TimeOut) )
    {
        if( __HAL_USART_IRDA_GET_FLAG(pHIrda, USART_IRDA_FLAG_RXNE) &&
            pHIrda->RxXferCount )
        {
            if( __HAL_USART_IRDA_GET_FLAG(pHIrda, USART_IRDA_FLAG_FE) )
            {
                pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_FE;
            }

            if( ptr16bitsrx )
            {
                *ptr16bitsrx = (pHIrda->Instance->DR & USART_IRDA_DR_9BIT);

                ptr16bitsrx++;
            }
            else
            {
                if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B ||
                    pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
                {
                    *ptr8bitsrx = (pHIrda->Instance->DR & USART_IRDA_DR_8BIT);
                }
                else
                {
                    *ptr8bitsrx = (pHIrda->Instance->DR & USART_IRDA_DR_7BIT);
                }

                ptr8bitsrx++;
            }

            pHIrda->RxXferCount--;
        }

        if( __HAL_USART_IRDA_GET_FLAG(pHIrda, USART_IRDA_FLAG_TXE) &&
            pHIrda->TxXferCount )
        {
            if( ptr16bitstx )
            {
                WRITE_REG(pHIrda->Instance->DR, (*ptr16bitstx & USART_IRDA_DR_9BIT) );

                ptr16bitstx++;
            }
            else
            {
                if( pHIrda->Init.WordLength == USART_IRDA_WORDLENGTH_9B ||
                    pHIrda->Init.Parity == USART_IRDA_PARITY_NONE )
                {
                    WRITE_REG(pHIrda->Instance->DR, (*ptr8bitstx & USART_IRDA_DR_8BIT) );
                }
                else
                {
                    WRITE_REG(pHIrda->Instance->DR, (*ptr8bitstx & USART_IRDA_DR_7BIT) );
                }

                ptr8bitstx++;
            }

            pHIrda->TxXferCount--;
        }
    }

    if( pHIrda->TxXferCount ||
        pHIrda->RxXferCount )
    {
        rval = HAL_TIMEOUT;
    }

    if( pHIrda->ErrorCode != HAL_USART_IRDA_ERROR_NONE )
    {
        rval = HAL_ERROR;
    }

    __HAL_UNLOCK(pHIrda);

    pHIrda->gState  = HAL_USART_IRDA_STATE_READY;
    pHIrda->RxState = HAL_USART_IRDA_STATE_READY;

    return rval;
}


/**
  * @brief  Send an amount of data in non-blocking mode.
  * @note   When USART IrDA parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 provided through pData.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @retval HAL status
  * @note   The USART IrDA errors are not managed to avoid the overrun error.
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit_IT(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size)
{
    if( !pHIrda || !pData || !Size )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->pTxBuffPtr  = pData;
    pHIrda->TxXferCount = Size;
    pHIrda->TxXferSize  = Size;

    __HAL_UNLOCK(pHIrda);

    SET_BIT(pHIrda->Instance->CR1, USART_CR1_TXEIE);

    return HAL_OK;
}


/**
  * @brief  Receive an amount of data in non-blocking mode.
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the received data is handled as a set of uint16. In this case, Size must indicate the number
  *         of uint16 available through pRxData.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be received.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive_IT(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size)
{
    if( !pHIrda || !pData || !Size )
    {
        return HAL_ERROR;
    }

    if( pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->RxXferCount = Size;
    pHIrda->RxXferSize  = Size;
    pHIrda->pRxBuffPtr  = pData;

    __HAL_USART_IRDA_CLEAR_FEFLAG(pHIrda);

    __HAL_UNLOCK(pHIrda);

    SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
    SET_BIT(pHIrda->Instance->CR3, USART_CR3_EIE);

    return HAL_OK;
}


/**
  * @brief  Send and Receive an amount of data in IrDA mode (non-blocking).
  * @note   When USART parity is not enabled, and Word Length is configured to 9 bits,
  *         the sent data and the received data are handled as sets of uint16. In this case, size must indicate the number
  *         of uint16 available through pTxData and through pRxData.
  * @param  pHUsart   Pointer to a USART_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to TX data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to RX data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent (same amount to be received).
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_TransmitReceive_IT(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize)
{
    if( !pHIrda || !pHIrda->Instance ||
        !TxSize || !RxSize ||
        !pTxData || !pRxData )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY ||
        pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->ErrorCode   = HAL_USART_IRDA_ERROR_NONE;
    pHIrda->pTxBuffPtr  = pTxData;
    pHIrda->pRxBuffPtr  = pRxData;
    pHIrda->TxXferCount = TxSize;
    pHIrda->TxXferSize  = TxSize;
    pHIrda->RxXferCount = RxSize;
    pHIrda->RxXferSize  = RxSize;

    __HAL_USART_IRDA_CLEAR_FEFLAG(pHIrda);

    __HAL_UNLOCK(pHIrda);

    SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE) );
    SET_BIT(pHIrda->Instance->CR3, USART_CR3_EIE);

    return HAL_OK;
}


/**
  * @brief  Abort ongoing transfer (blocking mode).
  * @param  pHIrda USART IrDA handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Abort(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_TCIE) );
    CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_EIE | USART_CR3_DMAR | USART_CR3_DMAT) );

    pHIrda->TxXferCount = 0U;
    pHIrda->RxXferCount = 0U;

    pHIrda->gState = HAL_USART_IRDA_STATE_READY;
    pHIrda->RxState = HAL_USART_IRDA_STATE_READY;

    HAL_USART_IRDA_AbortCpltCallback(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Abort ongoing transmit data.(blocking mode)
  * @param  pHUsart USART handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_AbortTransmit(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
    CLEAR_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);

    pHIrda->TxXferCount = 0U;

    pHIrda->gState = HAL_USART_IRDA_STATE_READY;

    HAL_USART_IRDA_AbortTransmitCpltCallback(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Abort ongoing receive data.(blocking mode)
  * @param  pHUsart USART handle.
  * @note   This procedure could be used for aborting any ongoing transfer.
  *         This procedure is executed in blocking mode : when exiting function, Abort is considered as completed.
  * @retval HAL status
  */
HAL_StatusTypeDef HAL_USART_IRDA_AbortReceive(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
    CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_EIE | USART_CR3_DMAR) );

    pHIrda->RxXferCount = 0U;

    pHIrda->RxState = HAL_USART_IRDA_STATE_READY;

    HAL_USART_IRDA_AbortReceiveCpltCallback(pHIrda);

    return HAL_OK;
}


/**
  * @brief  This function handles USART IrDA interrupt request.
  * @param  pHIrda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART IrDA module.
  * @retval None
  */
void HAL_USART_IRDA_IRQHandler(USART_IrDA_HandleTypeDef *pHIrda)
{
    HAL_StatusTypeDef   IsOK        = HAL_OK;
    uint32_t            error_flag  = 0U;
    uint32_t            reg_sr      = pHIrda->Instance->SR;
    uint32_t            reg1_it     = pHIrda->Instance->CR1;
    uint32_t            reg3_it     = pHIrda->Instance->CR3;

    error_flag = (pHIrda->Instance->SR & (USART_IRDA_FLAG_FE | USART_IRDA_FLAG_ORE | USART_IRDA_FLAG_PE | USART_IRDA_FLAG_NE) );

    if( (reg_sr & USART_IRDA_FLAG_RXNE) &&
        (reg1_it & USART_CR1_RXNEIE) )
    {
        IsOK = _USART_IRDA_Receive_IT(pHIrda);

        if( IsOK == HAL_OK && !pHIrda->RxXferCount )
        {
            HAL_USART_IRDA_RxCpltCallback(pHIrda);
        }

        if ( IsOK == HAL_BUSY )
        {
            pHIrda->ErrorCode = HAL_USART_IRDA_ERROR_CONFIG;

            HAL_USART_IRDA_ErrorCallback(pHIrda);
        }

        if( !error_flag )
        {
            return;
        }
    }

    if( error_flag &&
        ( (reg1_it & USART_CR1_PEIE) ||
        (reg3_it & USART_CR3_EIE) ) )
    {
        if( error_flag & USART_IRDA_FLAG_FE )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_FE;
        }

        if( error_flag & USART_IRDA_FLAG_NE )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_NE;
        }

        if( error_flag & USART_IRDA_FLAG_PE )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_PARITY;
        }

        if( error_flag & USART_IRDA_FLAG_ORE )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_ORE;

            __HAL_USART_IRDA_CLEAR_OREFLAG(pHIrda);
        }

        HAL_USART_IRDA_ErrorCallback(pHIrda);

        return;
    }

    if( (reg_sr & USART_IRDA_FLAG_TXE) &&
        (reg1_it & USART_CR1_TXEIE) )
    {
        IsOK = _USART_IRDA_Transmit_IT(pHIrda);

        if( IsOK == HAL_OK && !pHIrda->TxXferCount )
        {
            SET_BIT(pHIrda->Instance->CR1, USART_CR1_TCIE);
        }

        if( IsOK == HAL_BUSY )
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_CONFIG;

            HAL_USART_IRDA_ErrorCallback(pHIrda);
        }

        return;
    }

    if( (reg_sr & USART_IRDA_FLAG_TC) &&
        (reg1_it & USART_CR1_TCIE) )
    {
        CLEAR_BIT(pHIrda->Instance->CR1, USART_CR1_TCIE);

        if( !pHIrda->TxXferCount && (pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX) )
        {
            pHIrda->gState = HAL_USART_IRDA_STATE_READY;

            HAL_USART_IRDA_TxCpltCallback(pHIrda);
        }
        else
        {
            pHIrda->ErrorCode |= HAL_USART_IRDA_ERROR_CALLBACKS;

            HAL_USART_IRDA_ErrorCallback(pHIrda);
        }
        return;
    }
}


/**
  * @brief  Tx Transfer completed callbacks.
  * @param  pHIrda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART IrDA module.
  * @retval None
  */
__weak void HAL_USART_IRDA_TxCpltCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);
    /* NOTE: This function should not be modified, when the callback is needed,
            the HAL_USART_IRDA_TxCpltCallback could be implemented in the user file
    */
}


/**
  * @brief  Rx Transfer completed callbacks.
  * @param  pHIrda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART IrDA module.
  * @retval None
  */
__weak void HAL_USART_IRDA_RxCpltCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_IRDA_RxCpltCallback could be implemented in the user file
    */
}

/**
  * @brief  USART IrDA error callbacks.
  * @param  pHIrda   Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART IrDA module.
  * @retval None
  */
__weak void HAL_USART_IRDA_ErrorCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);
    /* NOTE: This function should not be modified, when the callback is needed,
           the HAL_USART_IRDA_ErrorCallback could be implemented in the user file
    */
}


/**
  * @brief  USART IrDA Abort Complete callback.
  * @param  pHIrda USART IrDA handle.
  * @retval None
  */
__weak void HAL_USART_IRDA_AbortCpltCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_IRDA_AbortCpltCallback can be implemented in the user file.
    */
}


/**
  * @brief  USART IrDA Transmit Abort Complete callback.
  * @param  pHIrda USART IrDA handle.
  * @retval None
  */
__weak void HAL_USART_IRDA_AbortTransmitCpltCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_IRDA_AbortTxCpltCallback can be implemented in the user file.
    */
}


/**
  * @brief  USART IrDA Receive Abort Complete callback.
  * @param  pHIrda USART IrDA handle.
  * @retval None
  */
__weak void HAL_USART_IRDA_AbortReceiveCpltCallback(USART_IrDA_HandleTypeDef *pHIrda)
{
    /* Prevent unused argument(s) compilation warning */
    UNUSED(pHIrda);

    /* NOTE : This function should not be modified, when the callback is needed,
            the HAL_USART_IRDA_AbortRxCpltCallback can be implemented in the user file.
    */
}


/**
  * @brief  Returns the USART IrDA state.
  * @param  pHIrda  Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART IrDA module.
  * @retval HAL state
  */
uint32_t HAL_USART_IRDA_GetState(USART_IrDA_HandleTypeDef *pHIrda)
{
    return (uint32_t)(pHIrda->gState | pHIrda->RxState);
}


/**
  * @brief  Return the USART IrDA error code
  * @param  pHIrda  Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                the configuration information for the specified USART.
  * @retval USART IrDA Error Code
  */
uint32_t HAL_USART_IRDA_GetError(USART_IrDA_HandleTypeDef *pHIrda)
{
    return (uint32_t)(pHIrda->ErrorCode);
}


#if defined(HAL_DMA_MODULE_ENABLED)
/**
  * @brief  DMA module is used to control USART IrDA to send quantitative data.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be sent.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit_DMA(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size)
{
    HAL_StatusTypeDef IsOK = HAL_OK;

    if( !pHIrda || !pHIrda->Instance ||
        !pData || !Size )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->pTxBuffPtr  = pData;
    pHIrda->TxXferCount = Size;
    pHIrda->TxXferSize  = Size;

    __HAL_USART_DISABLE(pHIrda);
    IsOK = _USART_IRDA_Transmit_DMA_Config(pHIrda);
    __HAL_USART_ENABLE(pHIrda);

    if( IsOK != HAL_OK )
    {
        pHIrda->gState = HAL_USART_IRDA_STATE_READY;
        return IsOK;
    }

    __HAL_UNLOCK(pHIrda);

    SET_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
    SET_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);

    return IsOK;
}


/**
  * @brief  DMA module is used to control USART IrDA to receive quantitative data.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pData   Pointer to data buffer (uint8 or uint16 data elements).
  * @param  Size    Amount of data elements (uint8 or uint16) to be receive.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive_DMA(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pData, uint16_t Size)
{
    HAL_StatusTypeDef IsOK = HAL_OK;

    if( !pHIrda || !pHIrda->Instance ||
        !pData || !Size )
    {
        return HAL_ERROR;
    }

    if( pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->RxXferCount = Size;
    pHIrda->RxXferSize  = Size;
    pHIrda->pRxBuffPtr  = pData;

    __HAL_USART_DISABLE(pHIrda);
    IsOK = _USART_IRDA_Receive_DMA_Config(pHIrda);
    __HAL_USART_ENABLE(pHIrda);

    __HAL_UNLOCK(pHIrda);

    if( IsOK != HAL_OK )
    {
        pHIrda->RxState = HAL_USART_IRDA_STATE_READY;
        return IsOK;
    }

    SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
    SET_BIT(pHIrda->Instance->CR3, USART_CR3_DMAR);

    return IsOK;
}


/**
  * @brief  The DMA module is used to control the USART IrDA to send and receive data.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @param  pTxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  pRxData Pointer to data buffer (uint8 or uint16 data elements).
  * @param  TxSize  Amount of data elements (uint8 or uint16) to be sent.
  * @param  RxSize  Amount of data elements (uint8 or uint16) to be receive.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_TransmitReceive_DMA(USART_IrDA_HandleTypeDef *pHIrda, uint8_t *pTxData, uint16_t TxSize, uint8_t *pRxData, uint16_t RxSize)
{
    HAL_StatusTypeDef R_IsOK = HAL_OK;
    HAL_StatusTypeDef T_IsOK = HAL_OK;

    if( !pHIrda ||
        !pTxData || !pRxData ||
        !TxSize || !RxSize )
    {
        return HAL_ERROR;
    }

    if( pHIrda->gState != HAL_USART_IRDA_STATE_READY ||
        pHIrda->RxState != HAL_USART_IRDA_STATE_READY )
    {
        return HAL_BUSY;
    }

    __HAL_LOCK(pHIrda);

    pHIrda->gState      = HAL_USART_IRDA_STATE_BUSY_TX;
    pHIrda->RxState     = HAL_USART_IRDA_STATE_BUSY_RX;
    pHIrda->TxXferCount = TxSize;
    pHIrda->TxXferSize  = TxSize;
    pHIrda->RxXferCount = RxSize;
    pHIrda->RxXferSize  = RxSize;
    pHIrda->pTxBuffPtr  = pTxData;
    pHIrda->pRxBuffPtr  = pRxData;

    __HAL_USART_DISABLE(pHIrda);

    R_IsOK = _USART_IRDA_Receive_DMA_Config(pHIrda);
    T_IsOK = _USART_IRDA_Transmit_DMA_Config(pHIrda);

    __HAL_USART_ENABLE(pHIrda);

    __HAL_UNLOCK(pHIrda);

    if( T_IsOK != HAL_OK ||
        R_IsOK != HAL_OK )
    {
        pHIrda->gState  = HAL_USART_IRDA_STATE_READY;
        pHIrda->RxState = HAL_USART_IRDA_STATE_READY;
        return HAL_ERROR;
    }

    SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_TXEIE | USART_CR1_TCIE | USART_CR1_PEIE) );
    SET_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAT | USART_CR3_DMAR | USART_CR3_EIE) );

    return HAL_OK;
}


/**
  * @brief  Pauses the DMA Transfer.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_DMAPause(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        CLEAR_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
    }

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Resumes the DMA Transfer.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_DMAResume(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        SET_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
        SET_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
    }

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
        SET_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Stops the DMA Transfer.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_DMAStop(USART_IrDA_HandleTypeDef *pHIrda)
{
    HAL_DMA_Channel_TypeDef channelid;
    HAL_StatusTypeDef       IsOK  = HAL_OK;

    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        IsOK = _USART_IRDA_GetPDMAChannel(pHIrda, pHIrda->gState, &channelid);
        if( IsOK != HAL_OK )
        {
            __HAL_UNLOCK(pHIrda);
            return IsOK;
        }

        CLEAR_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );

        HAL_DMA_Channel_Stop(pHIrda->pHDma, channelid);

        pHIrda->gState = HAL_USART_IRDA_STATE_READY;
    }

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        IsOK = _USART_IRDA_GetPDMAChannel(pHIrda, pHIrda->RxState, &channelid);
        if( IsOK != HAL_OK )
        {
            __HAL_UNLOCK(pHIrda);
            return IsOK;
        }

        CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );

        HAL_DMA_Channel_Stop(pHIrda->pHDma, channelid);

        pHIrda->RxState = HAL_USART_IRDA_STATE_READY;
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Pauses the DMA Transmit.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit_DMAPause(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        CLEAR_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Resume the DMA Transfer.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit_DMAResume(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        SET_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );
        SET_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Stop the DMA Transfer.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Transmit_DMAStop(USART_IrDA_HandleTypeDef *pHIrda)
{
    HAL_DMA_Channel_TypeDef channelid;
    HAL_StatusTypeDef       IsOK  = HAL_OK;

    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->gState == HAL_USART_IRDA_STATE_BUSY_TX )
    {
        IsOK = _USART_IRDA_GetPDMAChannel(pHIrda, pHIrda->gState, &channelid);
        if( IsOK != HAL_OK )
        {
            __HAL_UNLOCK(pHIrda);
            return IsOK;
        }

        CLEAR_BIT(pHIrda->Instance->CR3, USART_CR3_DMAT);
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_TXEIE | USART_CR1_TCIE) );

        HAL_DMA_Channel_Stop(pHIrda->pHDma, channelid);

        pHIrda->gState = HAL_USART_IRDA_STATE_READY;
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Pause the DMA Receive.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive_DMAPause(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Resume the DMA Receive.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive_DMAResume(USART_IrDA_HandleTypeDef *pHIrda)
{
    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        SET_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );
        SET_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


/**
  * @brief  Stop the DMA Receive.
  * @param  pHIrda    Pointer to a USART_IrDA_HandleTypeDef structure that contains
  *                 the configuration information for the specified USART module.
  * @retval HAL Status
  */
HAL_StatusTypeDef HAL_USART_IRDA_Receive_DMAStop(USART_IrDA_HandleTypeDef *pHIrda)
{
    HAL_DMA_Channel_TypeDef channelid;
    HAL_StatusTypeDef       IsOK  = HAL_OK;

    if( !pHIrda ||
        !pHIrda->Instance )
    {
        return HAL_ERROR;
    }

    __HAL_LOCK(pHIrda);

    if( pHIrda->RxState == HAL_USART_IRDA_STATE_BUSY_RX )
    {
        IsOK = _USART_IRDA_GetPDMAChannel(pHIrda, pHIrda->RxState, &channelid);
        if( IsOK != HAL_OK )
        {
            __HAL_UNLOCK(pHIrda);
            return IsOK;
        }

        CLEAR_BIT(pHIrda->Instance->CR3, (USART_CR3_DMAR | USART_CR3_EIE) );
        CLEAR_BIT(pHIrda->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE) );

        HAL_DMA_Channel_Stop(pHIrda->pHDma, channelid);

        pHIrda->RxState = HAL_USART_IRDA_STATE_READY;
    }

    __HAL_UNLOCK(pHIrda);

    return HAL_OK;
}


#endif  /* End of HAL_DMA_MODULE_ENABLED */



/** End of USART_IrDA HAL module driver
 * @}
 */

#endif  /* End of HAL_USART_IRDA_MODULE_ENABLE */

